using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;

namespace WebApplication
{
	/// <summary>
	/// Summary description for OperatingRound2.
	/// </summary>
    public partial class OperatingRound2 : System.Web.UI.Page, System.Web.UI.ICallbackEventHandler
	{
        private void InitializeClientCallbacksWithoutPostbacks()
        {
            ClientScriptManager cm = Page.ClientScript;
            String cbReference = cm.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
            String callbackScript = "function CallServer(arg, context) {" + cbReference + "; }";
            cm.RegisterClientScriptBlock(this.GetType(), "CallServer", callbackScript, true);
        }
        
        public void RaiseCallbackEvent(String eventArgument)
        {
        }

        public string GetCallbackResult()
        {
            string  sReturn = "";
            Game game = Global.getGame(this);
            string sPlayer = Session["PlayerName"] as string;
            
            Player player = game.Players[sPlayer];
            
            if (player.UpdateScreen)
            {
                player.UpdateScreen = false;
                
                if (game.GoToStockRound)
                {
                    sReturn = "Stock Round";
                }
/*                
                else if ((game.CGRForming) && (!game.CgrOptionalTokenReplacement) && (!game.CGRFormed))
                {
                    sReturn = "CGR";
                }                
 */
                else
                {
                    sReturn = "refresh";
//                    Response.Redirect("OperatingRound2.aspx");
//                    this.Server.Transfer("OperatingRound2.aspx");
                }
            }

            if (game.PrivateCompanySale)
            {
                sReturn = "refresh";
            }

            return sReturn;
        }

	
		static private	int	_mostRecentDividend;

		public int hexWidth
		{
			get { return WebApplication.GameboardHex.hexWidth; }
		}

		public int hexHeight
		{
			get { return WebApplication.GameboardHex.hexWidth; }
		}

		const string sFontName = "Arial Narrow";
		
		const int mapRowHeight = 71;  
		const int mapLeftMarginWidth = 40;
		const float mapColumnWidth = 61.7f;
		const int mapTopMarginHeight = 29; 

		void DisplayError (string sError)
		{
			OperatingRoundOutput.Text = sError;
			OperatingRoundOutput.ForeColor = Color.Red;
			OperatingRoundOutput.Font.Bold = true;
		}

		bool OperatingRoundInitialized ()
		{
			Game	game = Global.getGame (this);;
			bool	bReturn = true;

			if ((game.History[0] == "Next Operating Round") || (game.History[0] == "Go To Operating Round"))
				bReturn = false;

			return bReturn;
		}

		bool InitializeOperatingRound ()
		{
			Game	game = Global.getGame (this);;
			bool	bReturn = false;

			if (!game.OperatingRoundBeingInitialized)
			{
				game.OperatingRoundBeingInitialized = true;
				game.History.Clear ();
				game.History.Add ("Operating Round");

				game.PayoutPrivates();

				foreach (PublicCompany publicCompany in game.PublicCompanies)
					publicCompany.ResetOperatingRoundRuntimeVariables ();

				game.CurrentlyOperatingCompany = null;
                game.SetNextCompanyToOperate();
                game.OperatingRoundBeingInitialized = false;
                bReturn = true;
			}

			return bReturn;
		}

		private void DisplayCompanyInfo (PublicCompany currentPublicCompany)
		{
			string	sCompanyInfo;
			bool	bFirstTrain = true;

			if (currentPublicCompany == null)
			{
				this.CompanyInfo.Text = "Currently running company is null";
				return;
			}

			sCompanyInfo = currentPublicCompany.Name + ", cash $" + currentPublicCompany.Cash;
			
			if (currentPublicCompany.Loans > 0)
			{
			    sCompanyInfo += "<br/>" + "Loans: " + currentPublicCompany.Loans;
			}
			//			sCompanyInfo += "<br></br>" + "loans: " + currentPublicCompany.Loans;	// 2 spaces???  Huh???

			sCompanyInfo += "<br/>" + "Trains: ";

			foreach (Train train in currentPublicCompany.Trains)
			{
				if (!bFirstTrain)
				{
					sCompanyInfo += ", ";
				}

				bFirstTrain = false;
				sCompanyInfo += train.Name;
			}

            if (currentPublicCompany.StockMarketPosition != null)   // JWF 10.31.2007  During CGR formation this could occur
            {
			    sCompanyInfo += "<br/>" + "Stock value: $" + currentPublicCompany.StockMarketPosition.Value.ToString();
			}

			if (currentPublicCompany.NeedDestination)
			{
				sCompanyInfo += "<br/>" + "Destination: " + currentPublicCompany.Destination;
			}
			
            sCompanyInfo += "<br/>" + "Tokens played: " + currentPublicCompany.TokensPlayed + ", Tokens left: " + (currentPublicCompany.Tokens - currentPublicCompany.TokensPlayed);
			this.CompanyInfo.Text = sCompanyInfo;
		}

		protected void Page_Load(object sender, System.EventArgs e)
		{
            try
            {
//                Game game = Global.getGame(this);
//                string sPlayer = Session["PlayerName"] as string;
//                Player player = game.Players[sPlayer];

//                if (this.IsCallback && !player.UpdateScreen)
                if (this.IsCallback)
                {
                    return;
                } 
                
                Game game = Global.getGame(this);
                string sPlayer = Session["PlayerName"] as string;
                Player player = game.Players[sPlayer];
                
                InitializeClientCallbacksWithoutPostbacks();
                		
                bool bCurrentlyOperatingPlayer = false;
                int nLeft = 0;
                int nTop = 0;
                PublicCompany currentPublicCompany = null;
			
                if (game.CgrOptionalTokenReplacement)
                {
                    SetTitle(sPlayer + "-CGR Optional Token Replacement");
                    PublicCompany cgrCompany = game.PublicCompanies["CGR"];  // need the cgr company for share creation
                    DisplayCompanyInfo(cgrCompany);
                }
                else
                {
                    SetTitle(sPlayer);

                    if (game.GameOver)
                    {
                        this.Server.Transfer("GameStatus.aspx");
                    }
                    
                    if (game.GoToStockRound)
                    {
                        this.Server.Transfer("StockRound.aspx");
                    }

//                    if (game.PrivateCompanySale)  JWF 11.13.2007  New screen updating mechanism needs to send everyone to private screen sales
                    if (game.PrivateCompanySalePending || game.PrivateCompanySale)
                    {
                        Server.Transfer("CompanyBuyPrivateCompany.aspx");
                    }

                    if (game.ExistingTrainPurchaseSale)
                    {
                        Server.Transfer("BuyExistingTrain.aspx");
                    }

                    if (game.CGRForming)
                    {
                        game.UpdateAllPlayers ();
                        Server.Transfer("CGRFormation.aspx");
                    }

                    if (!OperatingRoundInitialized())
                    {
                        if (!InitializeOperatingRound())
                        {
                            // We couldn't intialize the operating round because someone else is doing so.  Just return and come back later.
                            return;
                        }
                    }

                    // handle forced stock sale scenario
                    if (game.ForcedStockSalePending && game.ForcedStockSaleCompleted)
                    {
						//game.ForcedStockSalePlayer.Priority = game.ForcedStockSalePlayerPriority;
						// put the stock round priority back where it belongs (works if forced seller = SR prio player too)
						game.ForcedStockSalePlayer.Priority = false;
						game.ForcedStockSaleHadPriorityPlayer.Priority = true;

                        // did we fullfill the sale amount?
                        if (game.ForcedStockSaleFullfilled)
                        {
                            // transfer from player to bank and resume where we left off
                            game.ForcedStockSalePlayer.Cash -= game.ForcedStockSaleAmountNeeded;
                            game.Bank                       += game.ForcedStockSaleAmountNeeded;
                            
                            game.ForcedStockSalePending = false;
                            game.ForcedStockSaleCompany = null;
                            game.ForcedStockSalePlayer  = null;
                        }
                        else    // we didn't fullfill the sale amount, game over man
                        {
                            string sMsg = game.ForcedStockSalePlayer.Name + " went bankrupt, the game is over!";

                            game.History.Add(sMsg);
                            game.BankruptcyOccurred = true;
                            // we need to ensure we enter code below to end game
                        }
                    }
                    
                    currentPublicCompany = game.CurrentlyOperatingCompany;

                    if (currentPublicCompany == null || game.BankruptcyOccurred)
                    {
                        // game is over because we ran out of $$$ or someone went broke (probably Johnson...)
                        if (game.BankBusted || game.BankruptcyOccurred)
                        {
                            bool bGameOver = false;

                            if (game.BankruptcyOccurred)
                            {
                                bGameOver = true;
                            }
                            else
                            {
                                game.NumberOfOperatingRoundsLeft--;			// dec the number of OR's left

                                if (game.NumberOfOperatingRoundsLeft == 0)	// if none left, goto status page
                                    bGameOver = true;
                            }

                            // game over man!!!!
                            if (bGameOver)
                            {
                                game.GameOver = true;
                                game.UpdateAllPlayers();
                                Server.Transfer("GameStatus.aspx");
                            }
                        }

                        game.CurrentOperatingRound++;

                        if (game.CurrentOperatingRound >= game.NumberOfOperatingRounds)
                        {
                            game.GoToStockRound = true;
                            game.History.Clear();
                            game.History.Add("Stock Round");
                            game.SaveGame("");
                            game.UpdateAllPlayers();
//                            Server.Transfer("StockRound.aspx");		// time to go to stock round  JWF 11.15.2007  Exception
                            Response.Redirect("StockRound.aspx");		// time to go to stock round
                        }
                        else
                        {
                            game.GoToStockRound = false;
                            game.History.Clear();
                            game.History.Add("Next Operating Round");
                            game.UpdateAllPlayers();
                            Server.Transfer("OperatingRound2.aspx");	// handle going to 2nd or 3rd Operating Round.
                        }
                    }
                    else
                    {
                        DisplayCompanyInfo(currentPublicCompany);
                    }

                    if (currentPublicCompany.FoldIntoCGR)
                    {
                        game.SetNextCompanyToOperate();
                        this.Server.Transfer("OperatingRound2.aspx");
                    }

                    string sCurrentlyOperatingOwner;

                    sCurrentlyOperatingOwner = game.CurrentOperatingOwner();

                    if (sCurrentlyOperatingOwner == sPlayer)
                        bCurrentlyOperatingPlayer = true;
                    else
                        bCurrentlyOperatingPlayer = false;

                    DisplayCurrentPhaseInfo(game, currentPublicCompany, sCurrentlyOperatingOwner);
                }

                UpdateHistory(game);

                if (game.CgrOptionalTokenReplacement)
                {
                    EnableControls(false);

                    string sPresident = GetCgrPresident(game);

                    if (sPlayer.Equals(sPresident))
                    {
                        EnableCgrTokenReplacementControls();
                    }
                }
                else
                {
                    EnableControls(bCurrentlyOperatingPlayer);

//                    if (!this.IsPostBack && (currentPublicCompany != null) && bCurrentlyOperatingPlayer && (game.OperatingRoundPhase == eOperatingRoundPhase.RunTrains))
//                        RunTrains(currentPublicCompany);
                }

                DrawGameBoard(game, ref nLeft, ref nTop);

                this.PriorityCheckBox.Text = sPlayer;

                if (!game.CgrOptionalTokenReplacement)
                {
                    if (!this.IsPostBack && bCurrentlyOperatingPlayer)
                    {
                        LoadTilesLB();
                        ColorsRB.AutoPostBack = true;
                        hexTypeRB.AutoPostBack = true;
                        tilesLB.AutoPostBack = true;
                        InitializeCompany();  // JWF  12.1.2007  Bizarro bug where more then one player tries to initialize company could occur is this is outside this if clause
                    }
                }
            }
            catch (Exception ex)
            {
                Game game = Global.getGame(this);

                game.OperatingRoundBeingInitialized = false;    // JWF 11.24.2007  TODO  This could be a problem if not reset the board never updates however this isn't transacted so privates could get paid out twice and other bad stuff.
                DisplayError("Error in PageLoad (), OR: " + ex.Message);
                this.Trace.Warn (ex.Message);
            }
		}

        private void UpdateHistory(Game game)
        {
			// Joe: operating round Undo throws exception on DataBind() when there are fewer history lines
			// and the selection index is no longer valid.  So set the selected index down to 0 (it's restored
			// below).
			if (historyLB.SelectedIndex > 0)
				historyLB.SelectedIndex = 0;

            historyLB.DataSource = game.History;
            historyLB.DataBind();
            historyLB.SelectedIndex = historyLB.Items.Count - 1;
        }

        private void DrawGameBoard(Game game, ref int nLeft, ref int nTop)
        {
            foreach (GameboardHex hex in game.GameboardHexes)
            {
                ImageButton newButton;

                if (hex.Tile != null)
                {
                    newButton = new ImageButton();

                    if (GetTopLeftOfHex(hex.Location, ref nLeft, ref nTop))
                    {
                        newButton.Style["LEFT"] = nLeft.ToString();
                        newButton.Style["TOP"] = nTop.ToString();
                    }

                    newButton.Click += new System.Web.UI.ImageClickEventHandler(this.ImageButton1_Click);
                    hex.Button = newButton;
                    hex.DrawTile();      //  newButton.ImageUrl = oldButton.ImageUrl;
                    newButton.Height = 71;
                    newButton.Width = 83;
                    newButton.Visible = true;
                    newButton.Style["Z-INDEX"] = "200";
                    newButton.Style["POSITION"] = "absolute";
                    newButton.Style["runat"] = "server";
                    newButton.ID = hex.Location;
                    newButton.ToolTip = hex.Location;
                    newButton.EnableViewState = false;

                    this.TilesPlaceHolder.Controls.Add(newButton);
                }

                Token tokenToRemove = DrawTokens(ref nLeft, ref nTop, hex);

                if (tokenToRemove != null)
                {
                    hex.Tokens.Remove(tokenToRemove);
                }

                if (hex.PortPlacedHere)
                {
                    if (game.CGRFormed)
                    {
                        hex.PortPlacedHere = false;
                    }
                    else
                    {
                        nLeft = 0;
                        nTop = 0;

                        this.GetTopLeftOfHex(hex.Location, ref nLeft, ref nTop);
                        nLeft += 4;
                        nTop += 4;
                        ImageButton newPortButton = new ImageButton();

                        newPortButton.Click += new System.Web.UI.ImageClickEventHandler(this.ImageButton1_Click);
                        newPortButton.ImageUrl = "Tiles\\Port_001.jpg";

                        newPortButton.Style["LEFT"] = nLeft.ToString();
                        newPortButton.Style["TOP"] = nTop.ToString();
                        newPortButton.Height = 18;
                        newPortButton.Width = 27;
                        newPortButton.Visible = true;
                        newPortButton.Style["Z-INDEX"] = "250";	// Over tiles, under tokens.
                        newPortButton.Style["POSITION"] = "absolute";
                        newPortButton.Style["runat"] = "server";
                        newPortButton.ID = "PortPlaced";
                        newPortButton.ToolTip = hex.Location;
                        newPortButton.EnableViewState = false;
                        this.TilesPlaceHolder.Controls.Add(newPortButton);
                    }
                }
            }
        }

        private Token DrawTokens(ref int nLeft, ref int nTop, GameboardHex hex)
        {
            int nTokenCount;
            Token tokenToRemove = null;

            nTokenCount = 0;

            foreach (Token token in hex.Tokens)
            {
                DrawToken(ref nLeft, ref nTop, hex, ref nTokenCount, ref tokenToRemove, token);
            }
            
            return tokenToRemove;
        }

        private void DrawToken(ref int nLeft, ref int nTop, GameboardHex hex, ref int nTokenCount, ref Token tokenToRemove, Token token)
        {
            if ((token.Company.StockMarketPosition != null) && token.Company.Closed)
            {
                tokenToRemove = token;
            }

            nTokenCount++;
            this.GetTopLeftOfHex(hex.Location, ref nLeft, ref nTop);
            ImageButton newTokenButton = new ImageButton();

            newTokenButton.Click += new System.Web.UI.ImageClickEventHandler(this.ImageButton1_Click);
            newTokenButton.ImageUrl = "Tiles\\" + token.Company.Name + ".gif";

            hex.OffsetTokenInHex(nTokenCount, ref nLeft, ref nTop, token.LocationInHex);
            newTokenButton.Style["LEFT"] = nLeft.ToString();
            newTokenButton.Style["TOP"] = nTop.ToString();
            newTokenButton.Height = 24;
            newTokenButton.Width = 24;
            newTokenButton.Visible = true;
            newTokenButton.Style["Z-INDEX"] = "250";
            newTokenButton.Style["POSITION"] = "absolute";
            newTokenButton.Style["runat"] = "server";
            newTokenButton.ID = hex.Location + "," + token.Company.Name;
            newTokenButton.ToolTip = hex.Location;
            newTokenButton.EnableViewState = false;
            token.Button = newTokenButton;
            this.TilesPlaceHolder.Controls.Add(newTokenButton);
        }

        private void DisplayCurrentPhaseInfo(Game game, PublicCompany currentPublicCompany, string sCurrentlyOperatingOwner)
        {
            if (game.CompanyMustPlaceInitialToken)
            {
                this.currentPlayersTurn.Text = sCurrentlyOperatingOwner + ", " + currentPublicCompany.Name + ", " + " Place Initial Token";
            }
            else if (game.ExercisingTheCanadaCompany)
            {
                this.currentPlayersTurn.Text = sCurrentlyOperatingOwner + ", " + currentPublicCompany.Name + ", " + " Exercising Canada Company";
            }
            else if (game.ExercisingWaterlooTileLay)
            {
                this.currentPlayersTurn.Text = sCurrentlyOperatingOwner + ", " + currentPublicCompany.Name + ", " + " Exercising Waterloo tile lay";
            }
            else if (game.ExercisingWaterlooTokenPlacement)
            {
                this.currentPlayersTurn.Text = sCurrentlyOperatingOwner + ", " + currentPublicCompany.Name + ", " + " Exercising Waterloo token placement";
            }
            else if (game.ExercisingPort)
            {
                this.currentPlayersTurn.Text = sCurrentlyOperatingOwner + ", " + currentPublicCompany.Name + ", " + " Exercising Port";
            }
            else
            {
                this.currentPlayersTurn.Text = sCurrentlyOperatingOwner + ", " + currentPublicCompany.Name + ", " + game.OperatingRoundPhase.ToString();
            }
        }

        private void EnableCgrTokenReplacementControls()
        {
            this.TestRoutes.Visible = false;
            this.Tunnel.Visible = false;
            this.Bridge.Visible = false;
            this.UndoPB.Visible = false;
            this.Port.Visible = false;
            this.WaterlooAndSaugeen.Visible = false;
            this.TheCanadaCompany.Visible = false;
            this.TakeOutLoan.Visible = false;
            this.Discard4sPB.Visible = true;
            Done.Enabled = true;
            PriorityCheckBox.Checked = true;

            StringCollection possibleCgrReplacementTokens = Session["PossibleReplacementTokens"] as StringCollection;
            
            if (possibleCgrReplacementTokens != null)
            {
                this.PossibleCgrTokenReplacementListBox.Items.Clear ();
                
                foreach (string sPossibleReplacement in possibleCgrReplacementTokens)
                {
                    this.PossibleCgrTokenReplacementListBox.Items.Add (sPossibleReplacement);
                }
            }
            
            this.PossibleCgrTokenReplacementListBox.Visible = true;
        }

        private string GetCgrPresident(Game game)
        {
            string  sReturn = "";
            
            foreach (Player player in game.Players)
            {
                foreach (Share share in player.Shares)
                {
                    if (share.President && share.PublicCompany.Name.ToLower ().Equals ("cgr"))
                    {
                        sReturn = player.Name;
                        return sReturn;
                     }
                }
            }
            
            return sReturn;
        }

		private void SetTitle (string sNewTitle)
		{
			Game				game = Global.getGame (this);
			HtmlGenericControl	title = this.FindControl ("Title") as HtmlGenericControl;

			if (title != null)
				title.InnerText = sNewTitle;

			string	sOperatingRoundTitle;

			sOperatingRoundTitle = "Operating round " + (game.CurrentOperatingRound + 1) + " of " + game.NumberOfOperatingRounds;
			OperatingRoundTitle.Text = sNewTitle + "-" + sOperatingRoundTitle;

			if (game.CurrentOperatingRound == 0)
			{
				OperatingRoundTitle.ForeColor = Color.Green;
			}
			else if (game.CurrentOperatingRound == 1)
			{
				OperatingRoundTitle.ForeColor = Color.Blue;
			}
			else
			{
				OperatingRoundTitle.ForeColor = Color.Purple;
			}
		}

		private bool PlaceToken (GameboardHex hex, string sHex, Side tokenSide, bool bInitialToken)
		{
			bool			bReturn = false;  // true = success.
			Game			game = Global.getGame (this);;
			PublicCompany	currentPublicCompany;

			currentPublicCompany = game.CurrentlyOperatingCompany;

			if (currentPublicCompany == null)	// Huh?
			{
				DisplayError ("Unable to place station, current public company is null");
				return bReturn;
			}

			if (hex == null)
			{
				DisplayError ("Unable to place station, hex is null");
				return bReturn;
			}

			if (currentPublicCompany.TokensPlayed >= currentPublicCompany.Tokens)
			{
				DisplayError ("Unable to place station, company used all tokens already.");
				return bReturn;
			}

			int nTokenCost = 0;

			switch (currentPublicCompany.TokensPlayed)
			{
				case 0:
					nTokenCost = 0;
					break;
                case 1:
                    {
                        if (currentPublicCompany.Name == "CGR")
                            nTokenCost = 100;   // 100 for CGR
                        else
                            nTokenCost = 40;    // 40 for most companies
                    }
                    break;
				default:
					nTokenCost = 100;
					break;
			}

			if (game.ExercisingWaterlooTokenPlacement)
				nTokenCost = 0;

			if (nTokenCost > currentPublicCompany.Cash)
			{
				DisplayError ("Unable to place station, company doesn't have enough cash.");
				return bReturn;
			}

			int		nMaxTokens = hex.MaxTokens;

			if (nMaxTokens > 0)
			{
				if (hex.Tile != null)  //  A tile has been laid?
				{
					switch (hex.Tile.Color)
					{
						case Tile.eTileColor.Yellow:
							nMaxTokens = 1;
							break;

						case Tile.eTileColor.Green:
							nMaxTokens = 2;
							break;

						case Tile.eTileColor.Brown:
							nMaxTokens = 2;

							if ((hex.City == "Toronto")	|| (hex.City == "New York"))
							{
								nMaxTokens = 4;
							}
							break;

						case Tile.eTileColor.Gray:
							break;

						default:
						{
							GameException	e = new GameException ("Invalid tile color.");
							throw (e);
						}
					}
				}

				// Reserve spot for home tokens.

				Side	sideToReserve;

				if (hex.ReserveSpotForHomeStation (game, out sideToReserve))
				{
					nMaxTokens--;

					if (sideToReserve != null)	// In the case of Toronto make sure that CV gets it's side, SW to NW.  1830 is NYNH
					{
						if (sideToReserve.GetDirection () == "SW") // Toronto and CV
						{
							if ((hex.Tile == null) || (hex.Tile.Color == Tile.eTileColor.Green))
							{
								if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NW"))
								{
									if (currentPublicCompany.Name != "CV")
									{
										DisplayError ("Unable to place station because this spot is reserved for the CV.");
										return bReturn;
									}
								}
							}
						}
						else  // NYNH and New York in 1830
						{
						}
					}
				}
			}

			if ((hex.m_nNumTokens  >= nMaxTokens) && !bInitialToken)
			{
				DisplayError ("Unable to place station, no more room in hex for tokens.");
				return bReturn;
			}

			// Does this company already have a token in this hex.

			string	sNewID = sHex + "," + currentPublicCompany.Name;

			foreach (Token existingToken in hex.Tokens)
			{
				string	sCurrentID = sHex + "," + existingToken.Company.Name;

				if (sCurrentID == sNewID)
				{
					DisplayError ("Company already has a token in this hex.");
					return bReturn;
				}
			}

			currentPublicCompany.Cash -= nTokenCost;
			game.Bank				  += nTokenCost;
			
			currentPublicCompany.TokensPlayed++;

			Token		token = new Token ();

			token.LocationInHex = tokenSide; 
			token.Company = currentPublicCompany;
//			Button	button = new Button ();

//			button.Text = currentPublicCompany.Name;

			int nLeft = 1;
			int nTop = 1;

			if (GetTopLeftOfHex (sHex, ref nLeft, ref nTop))
			{
				currentPublicCompany.DeferredInitialTokenPlacement = false;
				game.CompanyMustPlaceInitialToken = false;

				hex.m_nNumTokens++;
				hex.OffsetTokenInHex (hex.m_nNumTokens, ref nLeft, ref nTop, token.LocationInHex);
		
				hex.Tokens.Add (token);
				int nTokenCount = hex.Tokens.Count - 1;
				Token tokenToRemove = null;
                DrawToken(ref nLeft, ref nTop, hex, ref nTokenCount, ref tokenToRemove, token);
				
				string	sMessage;
				sMessage = currentPublicCompany.Name + " placed token at " + hex.Location;
				game.History.Add(sMessage);
                UpdateHistory(game);
                currentPublicCompany.TokenHexes.Add(hex);
				bReturn = true;
//				this.TilesPlaceHolder.Controls.Add (token.Button);  
			}

			return bReturn;
		}

		private void PlaceInitialToken ()
		{
			string	sHex = "";
		
			GameboardHex	hex;
			Game			game = Global.getGame (this);;
			PublicCompany	currentPublicCompany;
			bool			bPlaceToken = true;

			currentPublicCompany = game.CurrentlyOperatingCompany;

			if (currentPublicCompany == null)
				return;

			sHex = currentPublicCompany.Home;
			hex = game.GameboardHexes.Find (sHex);

			if (hex == null)
			{
				DisplayError ("Unable to place home station, can't find hex " + sHex);
				return;
			}

			if (hex.SeperateCities)
			{
				if (!currentPublicCompany.StartSideSpecified)	// THB in 1856, ERIE in 1830.
				{
					if (hex.Tile == null) // If no tile has been played, defer initial token placement until after a tile is laid.
					{
						currentPublicCompany.DeferredInitialTokenPlacement = true;
						bPlaceToken = false;
					}
					else  // A tile is in the hex.  If a tile has been played and there is already a token played in this hex then we already know the start side.
					{
						if (hex.Tile.Color == Tile.eTileColor.Gray)	// Hamilton 3 banger, side doesn't matter, set it to N.
						{
							currentPublicCompany.StartSide.SetDirection ("N");
						}
						else if (hex.Tokens.Count > 0)	// Green or brown tiles.  We can determine the start side if another token's in the hex.
						{
							Token	existingToken = hex.Tokens[0];
							Side	existingTokenSide = existingToken.LocationInHex;
							bool	bInitialTokenSideFound;

							foreach (Side startSide in hex.ExistingRoutes.Keys)
							{
								if (startSide.GetDirection () != existingTokenSide.GetDirection ())
								{
									SideCollection	sides = hex.ExistingRoutes[startSide] as SideCollection;
									bInitialTokenSideFound = true;

									foreach (Side endSide in sides)
									{
										if (endSide.GetDirection () == existingTokenSide.GetDirection ())
										{
											bInitialTokenSideFound = false;
											break;
										}
									}

									if (bInitialTokenSideFound)	// We found it.  Now set it and break.
									{
										bPlaceToken = true;
										currentPublicCompany.StartSide.SetDirection (startSide.GetDirection ());
										break;
									}
								}
							}
						}
						else	// There is a tile but no preexisting tokens.  User must choose a side before going on.
						{
							currentPublicCompany.DeferredInitialTokenPlacement = true;
							game.CompanyMustPlaceInitialToken = true;
							this.currentPlayersTurn.Text = game.CurrentOperatingOwner () + ", " + currentPublicCompany.Name + ", " + " Place Initial Token";
							bPlaceToken = false;
						}
					}
				}
			}

			if (bPlaceToken)
			{
				PlaceToken (hex, sHex, currentPublicCompany.StartSide, true);	// Only CV has a valid start side, THB has to pick and others don't care.
				currentPublicCompany.CheckForDestination ();
				
			}
		}

		private void InitializeCompany ()	// Lay initial token and mark it as having operated at least once.
		{
			Game			game = Global.getGame (this);;
			PublicCompany	currentPublicCompany;

			currentPublicCompany = game.CurrentlyOperatingCompany;

			if (currentPublicCompany != null)
			{
				if (!currentPublicCompany.Operated && currentPublicCompany.CanOperate)
				{
					PlaceInitialToken ();
					currentPublicCompany.Operated = true;
                    this.Server.Transfer("OperatingRound2.aspx");
				}
				else if (currentPublicCompany.DeferredInitialTokenPlacement)
				{
					if ((game.CurrentHex == null) || (game.CurrentHex.Length == 0))	// Is this company in the middle of laying a tile?
						PlaceInitialToken ();
				}
			}
		}

		private void LoadTilesLB ()
		{
			Game	game = Global.getGame (this);;
			string	sTileColor;
			string	sHexType;
			Tile.eTileColor eColor = Tile.eTileColor.Yellow;
			Tile.eTileTownType eTileTownType = Tile.eTileTownType.Unpopulated;
			tilesLB.Items.Clear ();
			sTileColor = ColorsRB.SelectedItem.Text;

			switch (sTileColor)
			{
				case "Yellow":
				{
					eColor = Tile.eTileColor.Yellow;
				}
					break;

				case "Green":
				{
					eColor = Tile.eTileColor.Green;
				}
					break;

				case "Brown":
				{
					eColor = Tile.eTileColor.Brown;
				}
					break;

				case "Gray":
				{
					eColor = Tile.eTileColor.Gray;
				}
					break;
			}

			sHexType = hexTypeRB.SelectedItem.Text;

			switch (sHexType)
			{
				case "Unpopulated":
				{
					eTileTownType = Tile.eTileTownType.Unpopulated;
				}
					break;

				case "City":
				{
					eTileTownType = Tile.eTileTownType.City;
				}
					break;

				case "Single Town":
				{
					eTileTownType = Tile.eTileTownType.Town;
				}
					break;

				case "Double Town":
				{
					eTileTownType = Tile.eTileTownType.DblTown;
				}
					break;
			}

			foreach (Tile tile in game.Tiles)
			{
				if (tile.Color == eColor)
				{
					if (tile.TownType == eTileTownType)
					{
						tilesLB.Items.Add (tile.Name);
					}
				}
			}

			if (tilesLB.Items.Count > 0)
				tilesLB.SelectedIndex = 0;
			ShowSelectedTile ();
		}

		void ShowSelectedTile ()
		{
			Game	game = Global.getGame (this);;
			string	sTile;
			string	sFile = "Tiles/";

			if (tilesLB.SelectedItem != null)
			{
				sTile = tilesLB.SelectedItem.Text;

				foreach (Tile tile in game.Tiles)
				{
					if (tile.Name == sTile)
					{
						this.TileQuantityLeft.Text = tile.QuantityLeft.ToString ();

						if (tile.QuantityLeft <= 0)
						{
							this.TileQuantityLeft.ForeColor = Color.Red;
						}
						else
						{
							this.TileQuantityLeft.ForeColor = Color.Black;
						}
						
						Session["Tile"] = tile;
						sFile += tile.File;
						break;
					}
				}

				selectedTile.ImageUrl = sFile;
			}
		}

		private void EnableControls (bool bEnable)
		{
			Game			game						= Global.getGame (this);;
			PublicCompany	currentlyOperatingCompany	= game.CurrentlyOperatingCompany;

            this.TestRoutes.Visible = false;
            this.Discard4sPB.Visible = false;
            
            if (bEnable)
            {
                this.TestRoutes.Visible = true;
                currentPlayersTurn.ForeColor = Color.DarkGreen;
                OperatingRoundTitle.ForeColor = Color.DarkGreen;
                CompanyInfo.ForeColor = Color.DarkGreen;
            }
            else
            {
                currentPlayersTurn.ForeColor = Color.Red;
                OperatingRoundTitle.ForeColor = Color.Red;
                CompanyInfo.ForeColor = Color.Red;
            }
                
            Done.Enabled = bEnable;
			this.UndoPB.Enabled = false;

//            if (bEnable && (game.OperatingRoundPhase != eOperatingRoundPhase.LayTile))
            if (bEnable)
			{
			    this.UndoPB.Enabled = true;
			}

			if (game.CompanyMustPlaceInitialToken)
				Done.Enabled = false;

			PriorityCheckBox.Enabled = false;
			tilesLB.Enabled = bEnable;
			this.ColorsRB.Enabled = bEnable;
			
			if (!game.GrayTilesAvailable)
			{
			    this.ColorsRB.Items.Remove ("Gray");
			}
			
            if (!game.BrownTilesAvailable)
            {
                this.ColorsRB.Items.Remove("Brown");
            }
            
            if (!game.GreenTilesAvailable)
            {
                this.ColorsRB.Items.Remove("Green");
            }
						
			this.hexTypeRB.Enabled = bEnable;

			// Disable refresh for the current player's turn.  Client side script will handle turning on/off the refresh.
            PriorityCheckBox.Checked = bEnable;
		
			// take out loan
			TakeOutLoan.Enabled = false;	

			if (bEnable && !game.CGRFormed && currentlyOperatingCompany.Open && !currentlyOperatingCompany.Closed)	//turn this off after CGR forms.
				TakeOutLoan.Enabled = currentlyOperatingCompany.CanTakeLoan;

			// buy privates
			BuyPrivate.Enabled = false;

			if (bEnable && currentlyOperatingCompany.Open && !currentlyOperatingCompany.Closed)
				BuyPrivate.Enabled = game.CanBuyPrivateCompanies;

			// run trains
            if (bEnable && (game.OperatingRoundPhase == eOperatingRoundPhase.RunTrains))
			{
                bool bPayoutEnabled = currentlyOperatingCompany.Trains.Count > 0;

                // CGR must have a permanant train or hold until it gets one
                if (currentlyOperatingCompany.Name == "CGR")
                {
                    // CGR must hold if is has no permanant or it is borrowing a train
                    bPayoutEnabled = currentlyOperatingCompany.HasPermanantTrain() && !currentlyOperatingCompany.BorrowingTrain;
                }

                //TakeOutLoan.Enabled = false;	// Joe: no need to disable Loan when running (work item 2465)
                PayOut.Enabled      = bPayoutEnabled;		
				Hold.Enabled		= bEnable;		
				Done.Enabled		= false;
			}
			else
			{
				PayOut.Enabled  = false;		
				Hold.Enabled    = false;		
			}

			// buy trains
			if (game.OperatingRoundPhase == eOperatingRoundPhase.BuyTrains && currentlyOperatingCompany.Open && !currentlyOperatingCompany.Closed)
			{
				BuyTrain.Enabled = bEnable;		

				// do we have a route but no trains?  If so, must buy a train
				if (currentlyOperatingCompany.HasARoute && currentlyOperatingCompany.Trains.Count == 0)
					Done.Enabled = false;
			}
			else
				BuyTrain.Enabled = false;		

			// redeem loans
			if ((game.OperatingRoundPhase == eOperatingRoundPhase.RedeemLoans && currentlyOperatingCompany.Open && !currentlyOperatingCompany.Closed) && bEnable)
			{
				if (currentlyOperatingCompany.MustRedeemLoans)
				{
					RepayLoan.Enabled = bEnable;
					Done.Enabled = false;
				}
				else if (currentlyOperatingCompany.Cash >= 100 && currentlyOperatingCompany.Loans > 0)
					RepayLoan.Enabled = bEnable;
				else	// go to next phase.
					PhaseOver ();
			}
			else
				RepayLoan.Enabled = false;

			TheCanadaCompany.Visible = false;
			WaterlooAndSaugeen.Visible = false;
			Port.Visible = false;
			Bridge.Visible = false;
			Tunnel.Visible = false;

			PrivateCompany privateCompany = null;

			if ((currentlyOperatingCompany.Owns ("The Canada Company", ref privateCompany)) && bEnable)
			{
				GameboardHex	hex = game.GameboardHexes.Find (privateCompany.Home);

				if (hex != null)
				{
					if (hex.Tile == null)	// Is there a tile already laid?
					{
						this.TheCanadaCompany.Visible = true;

						if (game.OperatingRoundPhase == eOperatingRoundPhase.LayTile)
						{
							this.TheCanadaCompany.Enabled = bEnable;
						}
						else
						{
							this.TheCanadaCompany.Enabled = false;
						}
					}
				}
			}

			if ((currentlyOperatingCompany.Owns ("Waterloo Saugeen Railway Company", ref privateCompany)) && bEnable)
			{
				this.WaterlooAndSaugeen.Visible = true;

				if (game.OperatingRoundPhase == eOperatingRoundPhase.LayTile && !game.ExercisingWaterlooTileLay 
					&& !game.ExercisingWaterlooTokenPlacement && !game.ExercisingTheCanadaCompany)
				{
					this.WaterlooAndSaugeen.Enabled = bEnable;
				}
				else
				{
					this.WaterlooAndSaugeen.Enabled = false;
				}
			}

			if ((currentlyOperatingCompany.Owns ("Great Lakes Shipping Company", ref privateCompany)) && bEnable)
			{
				this.Port.Visible = true;
			}

			if ((game.TunnelAvailable () && !currentlyOperatingCompany.TunnelRights) && bEnable)
			{
				this.Tunnel.Visible = true;
			}

			if ((game.BridgeAvailable () && !currentlyOperatingCompany.BridgeRights) && bEnable)
			{
				this.Bridge.Visible = true;
			}
		}

		private bool GetTopLeftOfHex (string sHex, ref int nLeft, ref int nTop) // Given a hex, get the top/left coords.
		{
			bool	bReturn = true;
			char	cColumn;
			string	sRow;
			int		nRow;
			int		nColumn;

			cColumn = sHex[0];
			sRow = sHex.Substring (1);
			bReturn = int.TryParse (sRow, out nRow);
			
			if (!bReturn)
			{
			    return bReturn;
			}
			
			nColumn = cColumn - 'A';
			nLeft = (int) (mapLeftMarginWidth + nColumn * mapColumnWidth);
			nTop = mapTopMarginHeight;

			if ((nColumn % 2) == 1) // B, D, F, ... col 2, 4, 6, rows 1, 3, 5
			{
				nTop += mapRowHeight * (nRow / 2);
			}
			else  // A, C, E,... col 1, 3, 5, rows 2, 4, 6
			{
				nTop += mapRowHeight * (nRow / 2) - (mapRowHeight / 2);
			}

			return bReturn; // True if got the coords successfully.
		}

		private string CalculateHex (int X, int Y)
		{
			string	sHex = "";
			//			char []	aChars = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R' };
			//			char []	aChars = { 'A', 'B', 'C'}; // fails at runtime
			//			char []	aChars = { 'A', 'B'};  // works

			X -= mapLeftMarginWidth;

			if (X > 0)
			{
				X = (int) (X / mapColumnWidth);
				char c = 'A';
				int i = c;
				i += X;
				c = (char) (i);

				if (X < 'R')
				{
					sHex = c.ToString ();

					if ((X % 2) == 1) // B, D, F, ... 2, 4, 6
					{
						Y -= mapTopMarginHeight;
						Y /= mapRowHeight;
						Y *= 2;
						Y += 1;
					}
					else  // A, C, E, ... 1, 3, 5
					{
						Y -= mapTopMarginHeight;
						Y -=  mapRowHeight / 2;
						Y /= mapRowHeight;
						Y += 1;
						Y *= 2;
					}

					if (Y < 10)
					{
						sHex += "0";
					}

					sHex += Y.ToString ();
				}
			}

			return sHex;
		}

		private void PlacePort (GameboardHex hex)
		{
			Game			game = Global.getGame (this);;

			if (hex.CanPlacePortHere ())
			{
				hex.PortPlacedHere = true;
				game.History.Add ("Port placed at: " + hex.Location);
                UpdateHistory(game);
                game.ExercisingPort = false;

				PrivateCompany	privateCompany = null;	// Exercising the Great Lakes Shipping Co. forces it to close.

				if (game.CurrentlyOperatingCompany.Owns ("Great Lakes Shipping Company", ref privateCompany))
				{
					game.History.Add ("Great Lakes Shipping Co. closed after exercising.");
                    UpdateHistory(game);
                    game.CurrentlyOperatingCompany.PrivateCompanies.Remove(privateCompany);
					game.CurrentlyOperatingCompany.PortRights = true;
				}

				this.Server.Transfer ("OperatingRound2.aspx");
			}
			else
			{
				DisplayError ("Can't place port at: " + hex.Location);
			}
		}

		private void HexClickedOn (object sender, int nX, int nY)
		{
			if (this.PriorityCheckBox.Checked == false)  // TODO figure out a way to disable image buttons on the fly.
				return; 

			Game			game = Global.getGame (this);;
			GameboardHex	hex;
			string			sError = "";
			WebControl		buttonPushed = sender as WebControl;
			string			sHex;

			OperatingRoundOutput.Text = "  Object ID is: " + buttonPushed.ID;
			Tile	tile = Session["Tile"] as Tile;

            if (game.CgrOptionalTokenReplacement)
            {
			    if (buttonPushed.ID != "ImageButton1")
			    {
				    sHex = buttonPushed.ToolTip;
                    OperatingRoundOutput.Text += "  Hex: " + sHex;
                    hex = game.GameboardHexes.Find(sHex);            
				}
				else
				{
                    sHex = CalculateHex(nX, nY);
                    OperatingRoundOutput.Text += "  Hex: " + sHex;
                    hex = game.GameboardHexes.Find(sHex);
				}
				
				if (hex != null)
				{
				    if (game.CgrHasTokenInHex (hex))
				    {
				        return;
				    }
				
                    Side tokenSide = new Side();
                    hex.SetSideFromTileCoordinates (nX, nY, ref tokenSide);

                    foreach (PublicCompany publicCompany in game.PublicCompanies)
                    {
                        if (publicCompany.FoldIntoCGR)
                        {
                            foreach (GameboardHex currentHex in publicCompany.TokenHexes)
                            {
                                if (hex.Location == currentHex.Location)
                                {
                                    for (int nIndex = 0; nIndex < hex.Tokens.Count; nIndex++)
                                    {
                                        Token removalToken = hex.Tokens[nIndex];

                                        if (removalToken.Company.Name.Equals(publicCompany.Name))
                                        {
//                                            if (removalToken.LocationInHex.GetDirection().Equals(tokenSide.GetDirection()))
                                            if (removalToken.LocationInHex.Letter.Equals(tokenSide.Letter))
                                            {
                                                PublicCompany cgrCompany = game.PublicCompanies["CGR"];  // need the cgr company for share creation
                                                currentHex.Tokens.Remove(removalToken);
                                                Token CgrToken = new Token();
            
                                                CgrToken.LocationInHex = removalToken.LocationInHex;
                                                CgrToken.Company = cgrCompany;
                                                hex.Tokens.Add(CgrToken);
                                                cgrCompany.TokenHexes.Add(hex);
                                                cgrCompany.TokensPlayed++;

                                                StringCollection possibleCgrReplacementTokens = Session["PossibleReplacementTokens"] as StringCollection;
                                                
                                                for (int i = possibleCgrReplacementTokens.Count - 1; i >= 0; i--)
                                                {
                                                    if (possibleCgrReplacementTokens[i].ToLower ().StartsWith (hex.Location.ToLower ()))
                                                    {
                                                        possibleCgrReplacementTokens.Remove(possibleCgrReplacementTokens[i]);
                                                    }
                                                }
                                                
                                                if ((possibleCgrReplacementTokens.Count == 0) || (cgrCompany.TokensPlayed >= cgrCompany.Tokens))
                                                {
                                                    game.CgrOptionalTokenReplacement = false;
                                                    game.UpdateAllPlayers();
                                                    game.FormCGR_FinishCleanUp();
                                                    game.UpdateAllPlayers();
                                                }

                                                game.UpdateAllPlayers ();
                                                this.Server.Transfer("OperatingRound2.aspx");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }                     
                    
                }
				
                return;
            }


			if (buttonPushed.ID != "ImageButton1")
			{
				sHex = buttonPushed.ToolTip;
				hex = game.GameboardHexes.Find (sHex);

				if (game.ExercisingPort)
				{
					PlacePort (hex);
                    game.UpdateAllPlayers();
                    return;
				}

				if (game.ExercisingWaterlooTileLay || game.ExercisingTheCanadaCompany || 
					((game.OperatingRoundPhase == eOperatingRoundPhase.LayTile) && !game.CompanyMustPlaceInitialToken))
				{
					if (hex == null)
					{
						DisplayError ("Hex not found, try again please.");
						return;
					}

					if ((game.CurrentHex == null) || (game.CurrentHex.Length == 0))	// Have they laid a tile yet this round?
					{
						if (hex.Tile != null)
						{
							DoUpgradeDowngrade (hex, game, sHex);
						}
						else
						{
							LayTile (game, hex, sHex, tile, nX, nY);
						}

                        return;
					}

					if (game.CurrentHex != sHex)	// Can only rotate the most recently laid tile.
					{
						DisplayError ("Can only rotate the most recently laid tile.");
						return;
					}

					hex.Rotate ();
					hex.SetValidTileRotation (game, hex.Tile, game.CurrentlyOperatingCompany, ref sError);
					UpdateTokenLocations (hex);
					hex.DrawTile ();
                }
				else if (game.ExercisingWaterlooTokenPlacement || (game.OperatingRoundPhase == eOperatingRoundPhase.PlaceToken) || game.CompanyMustPlaceInitialToken)
				{
					Side			tokenSide = new Side ();

					if (CanPlayToken (hex, nX, nY, ref tokenSide))
					{
						bool	bTempCompanyMustPlayInitialToken = game.CompanyMustPlaceInitialToken;

						if (PlaceToken (hex, sHex, tokenSide, bTempCompanyMustPlayInitialToken))
						{
							this.DisplayCompanyInfo (game.CurrentlyOperatingCompany);

							if (!bTempCompanyMustPlayInitialToken)
							{
								if (game.ExercisingWaterlooTokenPlacement)
								{
									DonePlacingWaterlooToken ();
                                }
								else
								{
									PhaseOver ();
								}
							}
							else	// Update the screen since we no longer need an initial token placement.
							{
								this.Server.Transfer ("OperatingRound2.aspx");
							}
						}
					}
				}
			}
			else
			{
				sHex = CalculateHex (nX, nY);
				OperatingRoundOutput.Text += "  Hex: " + sHex;

				hex = game.GameboardHexes.Find (sHex);

				if (hex == null)
				{
					DisplayError ("No hex clicked on.");
					return;
				}

				if (game.ExercisingPort)
				{
					PlacePort (hex);
                    game.UpdateAllPlayers();
                    return;
				}

				if (game.ExercisingTheCanadaCompany)
				{
					PrivateCompany	privateCompany = game.CurrentlyOperatingCompany.PrivateCompanies["TCCO"];
	
					if (privateCompany == null)
					{
						DisplayError ("Null Canada Company.");
						return;
					}

					if (hex.Location != privateCompany.Home)
					{
						DisplayError ("Can only lay hex:" + privateCompany.Home);
						return;
					}
				}

				if (game.ExercisingWaterlooTileLay)
				{
					PrivateCompany	privateCompany = game.CurrentlyOperatingCompany.PrivateCompanies["WSRC"];
	
					if (privateCompany == null)
					{
						DisplayError ("Null Waterloo.");
						return;
					}

					if (hex.Location != privateCompany.Home)
					{
						DisplayError ("Can only lay hex:" + privateCompany.Home);
						return;
					}
				}

				LayTile (game, hex, sHex, tile, nX, nY);
            }
		}


		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
		
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{    

		}
		#endregion

		private bool IsHexReachableByCompany (GameboardHex hex, PublicCompany publicCompany)
		{
			Game			game = Global.getGame (this);;
			bool			bReturn = false;
			string			sMessage;

			if ((hex == null) || (publicCompany == null))
			{
				DisplayError ("Error: Either hex or publicCompany is null.");
				return bReturn;
			}

			publicCompany.CreateHexVisitations ();

			if (publicCompany.HexVisits.ContainsKey (hex.Location))
			{
				bReturn = true;
			}
			else
			{
				sMessage = "Hex: " + hex.Location + " not reachable by: " + publicCompany.Name;
				DisplayError (sMessage);
			}

			return bReturn;
		}

		private bool DoUpgrade (Game game, string sHex, ref string sError)
		{
			Tile			tile = Session["Tile"] as Tile;
			bool			bReturn = false;
			GameboardHex	hex;

			if (tile.QuantityLeft > 0)
			{
				hex = game.GameboardHexes.Find (sHex);

				if (hex == null)
				{
					sError = "Hex not found, try again please.";
					return bReturn;
				}
				
				bReturn = hex.UpgradeTo (game, tile, ref sError);
			}
			else
			{
				sError = "No more tiles left.";
			}

			return bReturn;
		}

		private bool DoDowngrade (Game game, string sHex, ref string sError)
		{
			Tile			tile = Session["Tile"] as Tile;
			bool			bReturn = false;
			GameboardHex	hex;

			if (tile.QuantityLeft > 0)
			{
				hex = game.GameboardHexes.Find (sHex);

				if (hex == null)
				{
					sError = "Hex not found, try again please.";
					return bReturn;
				}
				
				bReturn = hex.DowngradeTo (game, tile, ref sError);
			}
			else
			{
				sError = "No more tiles left.";
			}

			return bReturn;
		}

		private void DoUpgradeDowngrade (GameboardHex hex, Game game, string sHex)
		{
			Tile			tile = Session["Tile"] as Tile;
			string			sError = "";

			if (!IsHexReachableByCompany (hex, game.CurrentlyOperatingCompany))
			{
				return;
			}

			if (DoUpgrade (game, sHex, ref sError))
			{
				game.CurrentHex = sHex;
				this.TileQuantityLeft.Text = tile.QuantityLeft.ToString ();
				UpdateTokenLocations (hex);
			}
			else if (DoDowngrade (game, sHex, ref sError))
			{
				game.CurrentHex = sHex;
				this.TileQuantityLeft.Text = tile.QuantityLeft.ToString ();
			}
			else
			{
				if (sError.Length > 0)
				{
					DisplayError (sError);
				}
			}
		}

		private bool CanPlayToken (GameboardHex hex, int nX, int nY, ref Side tokenSide)
		{
			Game			game = Global.getGame (this);;
			bool			bSeperateCitiesHaveMergedIntoOne = false;
			bool			bReturn = true;

			if (hex == null)
			{
				DisplayError ("Hex not found, try again please.");
				return false;
			}

			if (!game.ExercisingWaterlooTokenPlacement && !IsHexReachableByCompany (hex, game.CurrentlyOperatingCompany))
			{
				return false;
			}

            if (!game.ExercisingWaterlooTokenPlacement && !hex.CanCompanyReachAndHasRouteToToken(game.CurrentlyOperatingCompany))
			{
                DisplayError("Route to city not found, can't token.");
                return false;
			}

			if (hex.Tile != null)
			{
				if (hex.Tile.Name == "123")	// Gray Hamilton tile?
				{
					bSeperateCitiesHaveMergedIntoOne = true;
				}
			}

			if (game.ExercisingWaterlooTokenPlacement)
			{
				bReturn = false;
				GameboardHex	waterlooHex = game.GameboardHexes.Find ("I12");

				if (waterlooHex != null)
				{
					if (waterlooHex.Tile != null)	// Is there a tile already laid?
					{
						if (waterlooHex.m_nNumTokens  < waterlooHex.MaxTokens)	
						{
							if (hex == waterlooHex)
							{
								bReturn = hex.SetSideFromTileCoordinates (nX, nY, ref tokenSide);

								if (!bReturn || !hex.CanLayTokenOnThisSide (game, tokenSide))
								{
									DisplayError ("Can't lay token in this hex on that side.");
								}
							}
						}
					}
				}

				return bReturn;
			}

			if (!bSeperateCitiesHaveMergedIntoOne && hex.SeperateCities)	
			{
				bReturn = hex.SetSideFromTileCoordinates (nX, nY, ref tokenSide);

				if ((!bReturn || !hex.CanLayTokenOnThisSide (game, tokenSide)) && !game.CompanyMustPlaceInitialToken)
				{
					DisplayError ("Can't lay token in this hex on that side.");
					return false;
				}
			}

			return bReturn;
		}

		private void LayTile (Game game, GameboardHex hex, string sHex, Tile tile, int nX, int nY)
		{
			string		sError = ""; 

			if (game.OperatingRoundPhase == eOperatingRoundPhase.PlaceToken && !game.ExercisingTheCanadaCompany && !game.ExercisingWaterlooTileLay &&
				!game.ExercisingWaterlooTokenPlacement)
			{
				if (hex.City == "Toronto")		// Do we have to handle Kitchner and THB's home?
				{
					Side			tokenSide = new Side ();

					if (CanPlayToken (hex, nX, nY, ref tokenSide))
					{
						if (PlaceToken (hex, sHex, tokenSide, false))
						{
							this.DisplayCompanyInfo (game.CurrentlyOperatingCompany);
							PhaseOver ();
						}
					}
					else
					{
						DisplayError ("Can't place a token in Toronto.");
					}
				}
				else
				{
					DisplayError ("Can't place a token here.");
					return;
				}
				
				return;
			}

			if (game.TileAlreadyPlayed && !game.ExercisingTheCanadaCompany)
			{
				DisplayError ("Can only place one tile per turn.");
				return;
			}

			bool			bValidTileForHex = false;

			if (!game.ExercisingWaterlooTileLay && !game.ExercisingTheCanadaCompany && !IsHexReachableByCompany (hex, game.CurrentlyOperatingCompany))
			{
				return;
			}

			if (tile.QuantityLeft <= 0)
			{
				DisplayError ("This tile is no longer available.");
				return;
			}

			sError = "";
					
			if (hex.CanLayTile (game, ref sError))
			{
				int nLeft = 0;
				int nTop = 0;

				if (GetTopLeftOfHex (sHex, ref nLeft, ref nTop))
				{
					bValidTileForHex = hex.InitializeWithTile (game, tile, game.CurrentlyOperatingCompany, ref sError);

					if (bValidTileForHex)
					{
						if (!game.ExercisingTheCanadaCompany)
						{
							game.TileAlreadyPlayed = true;
						}

						tile.QuantityLeft--;
						this.TileQuantityLeft.Text = tile.QuantityLeft.ToString ();
						ImageButton b = new ImageButton ();

						b.Style["LEFT"] = nLeft.ToString ();
						b.Style["TOP"] = nTop.ToString ();
						b.Height = 71;
						b.Width = 83;
						b.Visible = true;
						b.Style["Z-INDEX"] = "200";
						b.Style["POSITION"] = "absolute";
						b.Style["runat"] = "server";
						b.ID = sHex;
						b.ToolTip = sHex;
						b.EnableViewState = false;
						hex.Button = b;
						UpdateTokenLocations (hex);
						hex.DrawTile ();

						if (hex.Cost > 0)
						{
							DisplayCompanyInfo (game.CurrentlyOperatingCompany);
						}

						foreach (Token token in hex.Tokens)
							this.TilesPlaceHolder.Controls.Add (token.Button);  // TODO, make sure this works.  Especially for undo as buttons aren't serialized.

						TilesPlaceHolder.Controls.Add (b);
						game.CurrentHex = sHex;
					}
					else
					{
						DisplayError (sError);
					}
				}
				else
				{
					DisplayError ("Unable to get top left of hex.");
				}
			}
			else
			{
				if (sError.Length > 0)
				{
					DisplayError (sError);
				}
				else
				{
					DisplayError ("Can't lay tile.");
				}
			}
		}

		protected void ImageButton1_Click(object sender, System.Web.UI.ImageClickEventArgs e)
		{
			HexClickedOn (sender, e.X, e.Y);
		}

		protected void ColorsRB_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			this.LoadTilesLB ();
		}

		protected void hexTypeRB_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			this.LoadTilesLB ();
		}

		protected void tilesLB_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			this.ShowSelectedTile ();
		}

		// operating round options handlers
		protected void TakeOutLoan_Click(object sender, System.EventArgs e)
		{
			Game			game	= Global.getGame (this);;
			string			sMsg;
			PublicCompany	company	= game.CurrentlyOperatingCompany;

			if (company.TakeOutLoan())
				sMsg = company.Name + " took out a loan";
			else
				sMsg = company.Name + " is at it's loan limit";
			
			game.History.Add(sMsg);
            UpdateHistory(game);
			
			DisplayCompanyInfo (company);
            game.UpdateAllPlayers();
			
			EnableControls (true);
		}
		
        protected void BuyPrivate_Click(object sender, System.EventArgs e)
		{
			Game			game	= Global.getGame (this);;
			PublicCompany	company	= game.CurrentlyOperatingCompany;

			game.ResetPrivateSaleInfo();
			game.PrivateCompanySalePending = true;
			game.PrivateCompanyBuyingCompany = company;
			game.PrivateCompanyPriorityPlayerName = game.CurrentOperatingOwner();
			game.UpdateAllPlayers ();

			Server.Transfer("CompanyBuyPrivateCompany.aspx");	// redirect buyer to buy screen
		}
		
        protected void PayOut_Click(object sender, System.EventArgs e)
		{
			Game			game	    = Global.getGame (this);
            bool            bBankBusted = game.BankBusted;
            string          sMsg;
            PublicCompany   company     = game.CurrentlyOperatingCompany;

			company.PayDividend(true, _mostRecentDividend);

            if (!bBankBusted && game.BankBusted)
                DisplayError("The bank is broke!!!");
            
            sMsg = company.Name + " pays out $" + (_mostRecentDividend / 10).ToString() + "/share";
            game.History.Add(sMsg);
            UpdateHistory (game);
            game.UpdateAllPlayers ();
            PhaseOver();
		}
		
        protected void Hold_Click(object sender, System.EventArgs e)
		{
			Game			game	    = Global.getGame (this);;
            bool            bBankBusted = game.BankBusted;
            string          sMsg;
            PublicCompany   company     = game.CurrentlyOperatingCompany;
			
			company.PayDividend(false, _mostRecentDividend);

            if (!bBankBusted && game.BankBusted)
                DisplayError("The bank is broke!!!");

            sMsg = company.Name + " holds for $" + _mostRecentDividend.ToString();
            game.History.Add(sMsg);
            UpdateHistory(game);
            game.UpdateAllPlayers();
            PhaseOver();
		}
		
        protected void BuyTrain_Click(object sender, System.EventArgs e)
		{
			Game			game	= Global.getGame (this);;
			PublicCompany	company	= game.CurrentlyOperatingCompany;

			Server.Transfer("BuyTrain.aspx");
		}
		
        protected void RepayLoan_Click(object sender, System.EventArgs e)
		{
            bool            bPaid   = false;
            Game			game	= Global.getGame (this);;
			string			sMsg;
			PublicCompany	company	= game.CurrentlyOperatingCompany;

            if (company.RepayLoan())
            {
                sMsg = company.Name + " repaid a loan";
                bPaid = true;
            }
            else
            {
                sMsg = company.Name + " doesn't have enough cash to repay a loan";
                bPaid = false;
            }

			game.History.Add(sMsg);
            UpdateHistory(game);
            this.DisplayCompanyInfo(company);
            
            // company forced to repay loans and can't pay
            if (company.MustRedeemLoans && !bPaid)
            {
                int nLoanAmount = 100;  // (100 - company.Cash);

                // 0. transfer all company cash to president (it will be < $100)
                company.Owner.Cash += company.Cash;
                company.Cash        = 0;
                
                // 1.  try to take the money from the president...
                if (company.Owner.Cash >= nLoanAmount)
                {
                    company.Owner.Cash -= nLoanAmount;
                    company.Cash       += nLoanAmount;
                    company.RepayLoan();
                    
                    sMsg = company.Owner.Name + " coughed $" + nLoanAmount.ToString() + " to repay a loan";
                    game.History.Add(sMsg);
                    UpdateHistory(game);
                }
                // 2.  if not, force a stock sale
                else
                {
                    int nForceSaleAmount = nLoanAmount - company.Owner.Cash;

                    // we need to temporarily pay off loan by giviing $100
                    company.Owner.Cash = nLoanAmount;
                    company.RepayLoan();
                    
                    // now take $ back from bank is it will be added back in if sale succeeds
                    game.Bank -= nLoanAmount;

                    // we should take all player cash and put into bank to keep books straight
                    game.PerformForcedStockSale(nLoanAmount, company);
                }
                // 3.  if not, player bankrupt, game over man
                    // goto game over phase!!!
            }

            game.UpdateAllPlayers ();
            EnableControls(true);
		}

		private bool FinishTileLay (Game game)
		{
			bool	bReturn = false;

			if ((game.CurrentHex != null) && (game.CurrentHex.Length > 0))
			{
				GameboardHex	hex = game.GameboardHexes[game.CurrentHex];

				if (hex != null)
				{
					hex.TransferTileRoutesToHex ();
					TrackSegment.CalculateHexRoutes (hex);

					if (game.CurrentlyOperatingCompany.DeferredInitialTokenPlacement) // Check to see if the THB, or Erie, needs to place it's initial token after laying a tile.
					{
						game.CompanyMustPlaceInitialToken = true;
					}

					game.CheckForDestinations ();
					bReturn = true;
				}

				game.CurrentHex = "";	// Reset so that the user can lay a new tile.
			}

			return bReturn;
		}

		protected void Done_Click(object sender, System.EventArgs e)
		{
			Game	game = Global.getGame (this);;

            if (game.CgrOptionalTokenReplacement)
            {
                game.CgrOptionalTokenReplacement = false;
                game.FormCGR_FinishCleanUp ();
                game.UpdateAllPlayers ();
                this.Server.Transfer("OperatingRound2.aspx");
            }

			if (game.ExercisingPort)
			{
				game.ExercisingPort = false;
                game.UpdateAllPlayers();
                Server.Transfer("OperatingRound2.aspx");
				return;
			}

			if (game.ExercisingTheCanadaCompany)
			{
				game.ExercisingTheCanadaCompany = false;
				FinishTileLay (game);
                game.UpdateAllPlayers();

				if (game.TileAlreadyPlayed)
				{
					PhaseOver ();
					return;
				}
				else
				{
                    Server.Transfer("OperatingRound2.aspx");
					return;					// Remain in Tile laying phase.
				}
			}

			if (game.ExercisingWaterlooTileLay)
			{
				game.ExercisingWaterlooTileLay = false;
				game.ExercisingWaterlooTokenPlacement = true;

				if (FinishTileLay (game))
				{
					PrivateCompany	privateCompany = null;	// Exercising the Waterloo and Saugeen forces it to close.

					if (game.CurrentlyOperatingCompany.Owns ("Waterloo Saugeen Railway Company", ref privateCompany))
					{
                        game.History.Add("Waterloo and Saugeen closed after exercising.");
                        UpdateHistory(game);
                        game.CurrentlyOperatingCompany.PrivateCompanies.Remove(privateCompany);
                        game.UpdateAllPlayers();
                    }
				}

//				PhaseOver ();
			}
			else if (game.ExercisingWaterlooTokenPlacement)  // Didn't actually place a token.
			{
                game.UpdateAllPlayers();
                game.ExercisingWaterlooTokenPlacement = false;
			}

			if (game.OperatingRoundPhase == eOperatingRoundPhase.LayTile)	// Translate the tile routes to hex routes.
			{
				FinishTileLay (game);
                game.UpdateAllPlayers();
            }

			PhaseOver ();
		}

		private void DonePlacingWaterlooToken ()
		{
			Game	game = Global.getGame (this);;

			game.ExercisingWaterlooTokenPlacement = false;
			PrivateCompany	privateCompany = null;	// Exercising the Waterloo and Saugeen forces it to close.

			if (game.CurrentlyOperatingCompany.Owns ("Waterloo Saugeen Railway Company", ref privateCompany))
			{
				game.History.Add ("Waterloo and Saugeen closed after exercising.");
                UpdateHistory(game);
                game.CurrentlyOperatingCompany.PrivateCompanies.Remove(privateCompany);
			}

			PhaseOver ();
		}

		private void PhaseOver ()
		{
			Game	game = Global.getGame (this);;

			game.CurrentHex = "";	// Disallow rotations of noncurrent hexes.

			if (game.IncrementOperatingRoundPhase ())
			{
                PublicCompany currentPublicCompany = game.CurrentlyOperatingCompany;
				
				currentPublicCompany.OperatedThisOperatingRound = true;
				game.SetNextCompanyToOperate ();

                game.UpdateAllPlayers();
                Server.Transfer("OperatingRound2.aspx");
            }
            else
            {
                string sPlayer = Session["PlayerName"].ToString();
                PublicCompany currentPublicCompany = game.CurrentlyOperatingCompany;
                DisplayCompanyInfo(currentPublicCompany);
                string sCurrentlyOperatingOwner;
                bool bCurrentlyOperatingPlayer = false;

                sCurrentlyOperatingOwner = game.CurrentOperatingOwner();
                
                if (game.OperatingRoundPhase == eOperatingRoundPhase.PlaceToken)
                {
                    if (!game.ExercisingWaterlooTokenPlacement)
                    {
                        if (!CanLayToken ())
                        {
                            game.IncrementOperatingRoundPhase ();
                        }
                    }    
                }

                if (sCurrentlyOperatingOwner == sPlayer)
                    bCurrentlyOperatingPlayer = true;
                else
                    bCurrentlyOperatingPlayer = false;

                DisplayCurrentPhaseInfo (game, currentPublicCompany, sCurrentlyOperatingOwner);

                if ((currentPublicCompany != null) && bCurrentlyOperatingPlayer && (game.OperatingRoundPhase == eOperatingRoundPhase.RunTrains))
                {
                    // CGR must have a permanant train or hold until it gets one
                    if (currentPublicCompany.Name == "CGR")
                    {
                        // if CGR has no train, it must borrow an 8 or D and hold until it has enough money
                        if (currentPublicCompany.Trains.Count == 0)
                        {
                            // if it never borrowed a train, get one.  If it had a permanant but sold it, no borrow allowed
                            if (!currentPublicCompany.BorrowedTrain && !currentPublicCompany.HadPermanantTrain)
                            {
                                string sTrain = "D";

                                if (game.MaxTrain8Train)
                                    sTrain = "8";

                                currentPublicCompany.BorrowedTrain = true;
                                currentPublicCompany.BorrowingTrain = true;
                                currentPublicCompany.BorrowedTrainName = sTrain;   // 8 or D

                                Train train = null;
                                TrainCollection trains = game.GetTrainCollectionFromType(sTrain);

                                train = trains[0];				           // get the train object
                                trains.Remove(train);		               // remove from game collection
                                currentPublicCompany.Trains.Add(train);    // add to CGR
                            }
                        }
                    }
                    
                    RunTrains(currentPublicCompany);                    
                }
                
                EnableControls(bCurrentlyOperatingPlayer);
            }

			//Response.Redirect("OperatingRound2.aspx");	// TODO  Research to see if there's a better way to do this.
//			Server.Transfer ("OperatingRound2.aspx");   // Do we really need to do this every time?
		}

        bool SpaceForAnotherToken (Game game, GameboardHex hex)
        {
            bool bReturn = true;

            int nMaxTokens = hex.MaxTokens;

            if (nMaxTokens > 0)
            {
                if (hex.Tile != null)  //  A tile has been laid?
                {
                    switch (hex.Tile.Color)
                    {
                        case Tile.eTileColor.Yellow:
                            nMaxTokens = 1;
                            break;

                        case Tile.eTileColor.Green:
                            nMaxTokens = 2;
                            break;

                        case Tile.eTileColor.Brown:
                            nMaxTokens = 2;

                            if ((hex.City == "Toronto") || (hex.City == "New York"))
                            {
                                nMaxTokens = 4;
                            }
                            break;

                        case Tile.eTileColor.Gray:
                            break;

                        default:
                            {
                                GameException e = new GameException("Invalid tile color.");
                                throw (e);
                            }
                    }
                }

                // Reserve spot for home tokens.

                Side sideToReserve;

                if (hex.ReserveSpotForHomeStation(game, out sideToReserve))
                {
                    nMaxTokens--;
                }
            }

            if (hex.m_nNumTokens >= nMaxTokens)
            {
                bReturn = false;
            }            
            
            return bReturn;
        }


// Check if the currently operating company can lay a token.  Does it have any tokens left?   Can it reach a tokenable city?  Do we need to check for money at some point?

        private bool CanLayToken()
        {
            bool bReturn = false;
            
            Game game = Global.getGame (this);
            
            if (game.CurrentlyOperatingCompany.TokensPlayed < game.CurrentlyOperatingCompany.Tokens)
            {
               if (!EnoughMoneyToToken (game))
               {
                    return false;
               }
                    
               game.CurrentlyOperatingCompany.CreateHexVisitations ();
                    
               foreach (HexVisit hexVisit in game.CurrentlyOperatingCompany.HexVisits.Values)
               {
                  if (hexVisit.Hex.CanCompanyReachAndHasRouteToToken (game.CurrentlyOperatingCompany))
                  {
                    bReturn = true;
                    
                    foreach (Token existingToken in hexVisit.Hex.Tokens)
                    {
                       if (existingToken.Company.Name.Equals (game.CurrentlyOperatingCompany.Name))  // Company Already has a token in this hex?
                       {
                            bReturn = false;
                            break;
                       }
                    }
                    
                    if (bReturn)
                    {
                        bReturn = SpaceForAnotherToken (game, hexVisit.Hex);
                        
                        if (bReturn)
                        {
                            return bReturn;
                        }
                    }
                  }
               }
            }
            
            return bReturn;
        }

        private bool EnoughMoneyToToken(Game game)
        {
            bool    bReturn = false;
            
            if ((game.CurrentlyOperatingCompany.Cash >= 100) || (game.CurrentlyOperatingCompany.CanTakeLoan && !game.CGRFormed))
            {
                bReturn = true;
            }
            else
            {
                if ((game.CurrentlyOperatingCompany.Cash >= 40) && (game.CurrentlyOperatingCompany.TokensPlayed == 1))
                {
                    bReturn = true;
                }
            }
            
            return bReturn;
        }

		private void RunTrains(PublicCompany company)
		{
            Game    game        = Global.getGame (this);
            int     nPlayerOwes = 0;
			bool	bPlayerOwes	= false;
            string  sMsg;

			_mostRecentDividend = company.RunTrains(out bPlayerOwes, out nPlayerOwes);
            sMsg = company.Name + " will run for $" + _mostRecentDividend;
            DisplayError(sMsg);

            // check if player owes money to pay off interest
            if (bPlayerOwes)
            {
                // 0. transfer all company cash to president (it will be < $10)
                company.Owner.Cash += company.Cash;
                company.Cash        = 0;

                // 1.  try to take the money from the president...
                if (company.Owner.Cash >= nPlayerOwes)
                {
                    company.Owner.Cash -= nPlayerOwes;
                    game.Bank          += nPlayerOwes;

                    sMsg = company.Owner.Name + " coughed $" + nPlayerOwes.ToString() + " to repay interest";
                    game.History.Add(sMsg);
                    UpdateHistory(game);
                }
                // 2.  if not, force a stock sale
                else
                {
                    int nForceSaleAmount = nPlayerOwes - company.Owner.Cash;

                    game.PerformForcedStockSale(nForceSaleAmount, company);
                }
                // 3.  if not, player bankrupt, game over man
                    // goto game over phase!!!
            }

            //game.History.Add(sMsg);
            //game.UpdateAllPlayers ();
            //PhaseOver ();// How to refresh the screen?
		}

		private void Token_Click (object sender, System.EventArgs e)
		{
			this.HexClickedOn (sender, 1, 1);
		}

		protected void StockMarket_Click(object sender, System.EventArgs e)
		{
			Game	game	= Global.getGame (this);;
			
			game.ViewStockMarketFromStockRound = false;
			Server.Transfer("StockMarket.aspx");
		}

		protected void GameStatus_Click(object sender, System.EventArgs e)
		{
			Game	game	= Global.getGame (this);;
			
			game.ViewGameStatusFromStockRound = false;
			Server.Transfer("GameStatus.aspx");
		}


		public void UpdateTokenLocations (GameboardHex hex)
		{
			int		nTokenCount = 0;

			foreach (Token token in hex.Tokens)
			{
				int		nLeft = 0;
				int		nTop = 0;

				nTokenCount++;
				this.GetTopLeftOfHex (hex.Location, ref nLeft, ref nTop);
				hex.OffsetTokenInHex (nTokenCount, ref nLeft, ref nTop, token.LocationInHex);
				token.Button.Style["LEFT"] = nLeft.ToString ();  // TODO  Test if this works with undo as buttons are not serialized.
				token.Button.Style["TOP"] = nTop.ToString ();
			}
		}

		protected void TheCanadaCompany_Click(object sender, System.EventArgs e)
		{
			Game	game = Global.getGame (this);;

			game.History.Add ("Exercising The Canada Company.");
            UpdateHistory(game);
            FinishTileLay(game);
			game.ExercisingTheCanadaCompany = true;
			Server.Transfer ("OperatingRound2.aspx");
		}

		protected void WaterlooAndSaugeen_Click(object sender, System.EventArgs e)
		{
			Game			game = Global.getGame (this);;
			PrivateCompany	privateCompany = null;	
			bool bReturn = FinishTileLay (game);
			game.History.Add ("Exercising the Waterloo and Saugeen.");
            UpdateHistory(game);

			if (bReturn)
			{
				game.ExercisingWaterlooTokenPlacement = true;
				Server.Transfer ("OperatingRound2.aspx");
				return;
			}

			if (game.CurrentlyOperatingCompany.Owns ("Waterloo Saugeen Railway Company", ref privateCompany))
			{
				GameboardHex	hex = game.GameboardHexes.Find (privateCompany.Home);

				if (hex != null)
				{
					if (hex.Tile == null)	// Is there a tile already laid?
					{
						game.ExercisingWaterlooTileLay = true;
					}
					else
					{
						game.ExercisingWaterlooTokenPlacement = true;
					}
				}
			}

			Server.Transfer ("OperatingRound2.aspx");
		}

		protected void Port_Click(object sender, System.EventArgs e)
		{
			Game			game = Global.getGame (this);;

			game.History.Add ("Exercising the Port.");
            UpdateHistory(game);
            game.ExercisingPort = true;
			Server.Transfer ("OperatingRound2.aspx");
		}

		protected void Bridge_Click(object sender, System.EventArgs e)
		{
			Game			game = Global.getGame (this);;

			if (game.CurrentlyOperatingCompany.Cash >= 50)
			{
				game.History.Add (game.CurrentlyOperatingCompany.Name + " bought Bridge rights.");
                UpdateHistory(game);
                game.PurchaseBridgeRights();
				Server.Transfer ("OperatingRound2.aspx");
			}
			else
			{
				DisplayError ("Insufficient funds.  Bridge costs $50.");
			}
		}

		protected void Tunnel_Click(object sender, System.EventArgs e)
		{
			Game			game = Global.getGame (this);;

			if (game.CurrentlyOperatingCompany.Cash >= 50)
			{
				game.History.Add (game.CurrentlyOperatingCompany.Name + " bought Tunnel rights.");
                UpdateHistory(game);
                game.PurchaseTunnelRights();
				Server.Transfer ("OperatingRound2.aspx");
			}
			else
			{
				DisplayError ("Insufficient funds.  Tunnel costs $50.");
			}
		}
		
        protected void TestRoutes_Click(object sender, System.EventArgs e)
        {
            Game game = Global.getGame (this);
            PublicCompany company = game.CurrentlyOperatingCompany;

            RouteCollection routes = RouteCollection.FindBestRoutes(company, company.Trains);
            string test = routes.ToString();
            int value = routes.TotalValue;
            System.Diagnostics.Trace.WriteLine("*** " + company.Name +
                " routes (value=" + value + "):\n" + test);

			string terseRoutes = routes.ToStringTerse("<br>");
			OperatingRoundOutput.Text = string.Format("{0} can run for ${1}<br>{2}", company.Name, value, terseRoutes);
        }

        protected void Discard4s_Click(object sender, System.EventArgs e)
        {
            Game game = Global.getGame(this);

            game.History.Add("Discarding CGR 4 trains.");
            UpdateHistory(game);
            game.Discard4s = true;
            Discard4sPB.Visible = false;
            Server.Transfer("OperatingRound2.aspx");
        }

        protected void UndoPB_Click(object sender, EventArgs e)
        {
            Game game = Global.getGame(this);
            
            if (!File.Exists(game.PathOfLastSavedGame))
            {
//                game.History.Add("Can't undo because file: " + game.PathOfLastSavedGame + " doesn't exist");
                this.DisplayError ("Can't undo because file: " + game.PathOfLastSavedGame + " doesn't exist");
                return;
            }
            
            try
            {
                Game restoredGame = Game.LoadGame(game.PathOfLastSavedGame);

                if (restoredGame != null)
                {
                    restoredGame.PathOfLastSavedGame = game.PathOfLastSavedGame;
                    restoredGame.History.Add("Undo done by player: " + game.CurrentOperatingOwner());
                    UpdateHistory(restoredGame);
                    Global.ReplaceGame(this, restoredGame);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLine(ex.ToString());
                game.History.Add ("LoadGame failed:\n" + ex.ToString());
                UpdateHistory(game);
                return;
            }

            game.UpdateAllPlayers ();
            Server.Transfer("OperatingRound2.aspx");    
        }
		
	}
}









